#include "rlock.h"
#include "rnet.h"
#include "app_service.h"
#include "app_read_task.h"
#include <json/reader.h>
#include <json/json.h>
using namespace	Json ;

short gsh_daemon_port = 9000 ;
int gi_client_idle = 5*60;

app_service::app_service():
	mp_control_task(NULL),
	mb_using(false)
{
}	

app_service::~app_service( )
{
	for ( map<int, app_task*>::iterator it = mm_task.begin() ; it != mm_task.end() ; it++ )
	{
		app_task* p_task = it->second ;
		rmutex(p_task->m_lock) ;
		del_task(*p_task) ;
		delete p_task ;
		p_task = NULL ;
	}
}

bool app_service::start()
{
	if ( !mservice_epoll.create(gsh_daemon_port) )
	{
		rlog << "mservice_epoll.create() error" << endl ;
		return false ;
	}

	pthread_t tid_clear ;
	if ( pthread_create(&tid_clear, NULL, epoll_clear_routine, this) != 0 )
	{
		rlog << "pthread_create() : epoll_clear_routine : " << strerror( errno ) << endl;
		return false;
	}

	pthread_t tid_wait;
	if ( pthread_create(&tid_wait, NULL, epoll_wait_routine, this) != 0 )
	{
		rlog << "pthread_create() : epoll_wait_routine : " << strerror( errno ) << endl;
		return false;
	}	

	pthread_t tid_accept;
	if ( pthread_create(&tid_accept, NULL, epoll_accept_routine, this) != 0 )
	{
		rlog << "pthread_create() : epoll_accept_routine : " << strerror( errno ) << endl;
		return false;
	}

	return true ;
}

void app_service::add_task( const int i_socket )
{
	map<int, app_task*>::iterator it = mm_task.find(i_socket) ;
	if ( it == mm_task.end() )
		mm_task[i_socket] = new app_task();

	app_task* p_task = mm_task.find(i_socket)->second ;
	rmutex(p_task->m_lock) ;
	p_task->init(i_socket);
	mservice_epoll.event_add(i_socket) ;
}

void app_service::del_task(app_task& r_task)
{
	if ( r_task.mi_type == _19dot5_APP )
	{
		mp_control_task = NULL ;
		mb_using = false ;
	}
	
	mservice_epoll.event_del(r_task.mi_fd);
	r_task.clear();
	
	r_task.mi_type = -1 ;
	r_task.ms_sn.clear();
	r_task.ms_version.clear();
	r_task.ms_vender.clear();
}

void app_service::del_task( const int i_socket )
{
	if ( i_socket == -1 )
		return ;
		
	map<int, app_task*>::iterator it = mm_task.find(i_socket) ;
	if ( it == mm_task.end() )
		return ;
		
	app_task* p_task = it->second ;	
	rmutex(p_task->m_lock) ;
	del_task(*p_task);
}

void app_service::do_display_app_update(const string& s_new_version, const string& s_path)
{
	if ( s_new_version.empty() )
	{
		rlog << "s_new_version empty" << endl;
		return ;
	}
	
	if( s_path.empty() )
	{
		rlog << "s_path empty" << endl;
		return ;
	}
		
	map<int, app_task*>::iterator it ;
	for ( it = mm_task.begin() ; it != mm_task.end() ; it++ )
	{
		app_task* p_task = it->second;
		rmutex(p_task->m_lock) ;
		if ( p_task->mi_type != _31dot5_APP )
			continue ;

		Value root ;
		root["update_path"] = s_path;
		root["update_version"] = s_new_version;
		if( rjson::write( p_task->mi_fd, root.toStyledString() ) < 0)
		{
			rlog << "json::write display app(" << p_task->mi_fd << ") error" << endl ;
			continue ;
		}

		rlog << "write display app(" << p_task->mi_fd << ") data" << endl << root.toStyledString() << endl ;
	}
}

void app_service::do_control_app_update(const string& s_new_version, const string& s_path)
{
	if ( s_new_version.empty() )
	{
		rlog << "s_new_version empty" << endl;
		return ;
	}
	
	if( s_path.empty() )
	{
		rlog << "s_path empty" << endl;
		return ;
	}

	map<int, app_task*>::iterator it ;
	for ( it = mm_task.begin() ; it != mm_task.end() ; it++ )
	{
		app_task* p_task = it->second;
		rmutex(p_task->m_lock) ;
		if ( p_task->mi_type != _19dot5_APP )
			continue ;

		Value root ;
		root["update_path"] = s_path;
		root["update_version"] = s_new_version;
		if ( rjson::write( p_task->mi_fd, root.toStyledString() ) < 0 )
		{
			rlog << "json::write control app(" << p_task->mi_fd << ") error" << endl ;
			break ;
		}

		rlog << "write control app(" << p_task->mi_fd << ") data" << endl << root.toStyledString() << endl ;
		break;
	}
}

void app_service::set_control_online(app_task* p_task)
{
	mp_control_task = p_task;
}

void app_service::write(const string& s_data)
{
	map<int, app_task*>::iterator it ;
	for ( it = mm_task.begin() ; it != mm_task.end() ; it++ )
	{
		app_task* p_task = it->second;
		rmutex(p_task->m_lock) ;
		if ( p_task->is_online() )
		{
			if ( rjson::write( p_task->mi_fd, s_data ) < 0 )
			{
				rlog << "json::write app(" << p_task->mi_fd << ") error" << endl ;
				continue ;
			}

			rlog << "write app(" << p_task->mi_fd << ") data" << endl << s_data << endl ;
		}
	}
}

void* app_service::epoll_accept_routine(void* arg)
{
	pthread_detach(pthread_self());

	if ( arg == NULL )
	{
		rlog << "argument = NULL" << endl ; 
		return NULL ;
	}
	
	app_service* p_this = reinterpret_cast<app_service*>( arg );
	p_this->epoll_accept_entry();

	return NULL;
}

void app_service::epoll_accept_entry(void)
{
	while( true )
	{
		int i_socket = mservice_epoll.accept() ;
		if ( i_socket < 0 )
		{
			rlog << "mservice_epoll.accept()" << endl ;
			continue ;
		}

		add_task(i_socket) ;
	}
}

void* app_service::epoll_wait_routine(void* arg)
{
	pthread_detach(pthread_self());
	
	if ( arg == NULL )
	{
		rlog << "argument = NULL" << endl ; 
		return NULL ;
	}
	
	app_service* p_this = reinterpret_cast<app_service*>( arg );
	p_this->epoll_wait_entry();

	return NULL;
}

void app_service::epoll_wait_entry(void)
{
	while(true) 
	{
		int nfds = mservice_epoll.wait() ;

		if(nfds == 0) 
			continue;

		if(nfds < 0)
		{
			rlog << "mservice_epoll.wait() error" << endl;
			continue ;
		}

		for(int i = 0; i < nfds; ++i)
		{
			int i_socket = mservice_epoll.mresult_event[i].data.fd ;

			rlog << "app(" << i_socket << ") event" << endl ;

			if ( mservice_epoll.mresult_event[i].events & EPOLLERR )
			{
				rlog << "app(" << i_socket << ") error event" << endl ;

				del_task(i_socket);
				continue ;
			}
			
			rthreadpool::_instance().add_task(new app_read_task(*mm_task[i_socket]));
		}
	}
}

void* app_service::epoll_clear_routine(void* arg)
{
	pthread_detach(pthread_self());

	if ( arg == NULL )
	{
		rlog << "argument = NULL" << endl ; 
		return NULL ;
	}
	
	app_service* p_this = reinterpret_cast<app_service*>( arg );
	p_this->epoll_clear_entry();

	return NULL;
}

void app_service::epoll_clear_entry(void)
{
	while(true) 
	{
		map<int, app_task*>::iterator it ;
		for( it = mm_task.begin() ; it != mm_task.end() ; it++ )
		{
			app_task* p_task = it->second ;
			rmutex(p_task->m_lock) ;
			if( p_task->mi_fd == -1 )
				continue ;
				
			if( time(NULL) - p_task->m_time > gi_client_idle ) 
			{
				rlog << "app(" << p_task->mi_fd << ") idle timeout error" << endl ;
				rjson::write_failure( p_task->mi_fd, "idle timeout error" ) ;

				del_task(*p_task);
			}
		}

		sleep(gi_client_idle) ;
	}
}

